/*$Copyright:
 * Copyright (C) 1992.5.22. Recruit Co.,Ltd. 
 * Institute for Supercomputing Research
 * All rights reserved.
 * NewsBase  by ISR, Kazuto MIYAI, Gary ARAKAKI, Katsunori SUZUKI, Kok-meng Lue
 *
 * You may freely copy, distribute and reuse the code in this program under 
 * following conditions.
 * - to include this notice in the source code, if it is to be distributed 
 *   with source code.
 * - to add the file named "COPYING" within the code, which shall include 
 *   GNU GENERAL PUBLIC LICENSE(*).
 * - to display an acknowledgement in binary code as follows: "This product
 *   includes software developed by Recruit Co.,Ltd., ISR."
 * - to display a notice which shall state that the users may freely copy,
 *   distribute and reuse the code in this program under GNU GENERAL PUBLIC
 *   LICENSE(*)
 * - to indicate the way to access the copy of GNU GENERAL PUBLIC LICENSE(*)
 *
 *   (*)GNU GENERAL PUBLIC LICENSE is stored in the file named COPYING
 * 
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
$*/

#import "IFolderDockMatrix.h"
#import "IFolderDockCell.h"
#import "IFolderTransparentWindow.h"
#import "Localization.h"
#import "errdebug.h"

#import <appkit/Font.h>
#import <appkit/NXImage.h>
#import <appkit/NXSplitView.h>
#import <appkit/Application.h>
#import <appkit/Panel.h>
#import <objc/List.h>

#import <math.h>
#import <string.h>

#define LoStr(key)      doLocalString(NULL,key,NULL)

//#define		DOCKCELL_W	160
#define		DOCKCELL_W	120
#define		DOCKCELL_H	76

@implementation IFolderDockMatrix

- initFrame:(NXRect *)frameRect
{
    NXSize	dockCellSize;
    id		dockProto;
    id		titleFont;

    // make proto type for matrix's cell
    dockProto = [[IFolderDockCell allocFromZone:[self zone]] 
    						initIconCell:BLANKICON];
    [dockProto setTitle:""];
    [dockProto setBordered:NO];
    [dockProto setIconPosition:NX_ICONABOVE];
    [dockProto setTarget:self];
    [dockProto setAction:@selector(selectNewsgroupInBrowser:)];
    titleFont = [Font newFont:TITLEFONT size:TITLEFONTSIZE];
    [dockProto setFont:titleFont];
    [dockProto setLeaf:YES];

    // compute # of rows and cols to fit into frameRect
    dockCellSize.width = DOCKCELL_W;
    dockCellSize.height = DOCKCELL_H;
    // make one cell which can hold root(nextStation) icon at least
    // after resizeing this view, columns and rows are added
    [super initFrame:frameRect mode:NX_TRACKMODE prototype:dockProto
			    			numRows:1 numCols:1];
    
    [self setCellSize:&dockCellSize];
    [self setBackgroundGray:NX_LTGRAY];
    [self setCellBackgroundGray:NX_LTGRAY];
    [self setEnabled:YES];
    
    isPalette = NO;
    // set transparentWindow class
    iTransparentWindowClass = [IFolderTransparentWindow class];
    
    // set file name which have information of dock
    strncpy (iDirFileName, NXHomeDirectory(), sizeof(iDirFileName)-1);
    if (strlen(iDirFileName) > (MAXPATHLEN-DIRFILELEN-1)) {
	// path name of home directory is too long
	fprintf(stderr,"NewsBase:IFolderDockMatrix: can't set dirfile name\n");
	iDirFileName[0] = '\0';
    } else {
	strncat (iDirFileName, DIRFILE, DIRFILELEN);
    }
    
    [self readDirFile];
    [self sizeToCells];
    
    return self;
}

- sizeTo:(NXCoord)width :(NXCoord)height
{
    int		ncols, nrows;
    int		i;
    NXSize	frameSize;
    
    DBG(10,fprintf(stderr," --size.width=%f\t size.height=%f\n",
		    		frame.size.width,frame.size.height));
    DBG(10,fprintf(stderr," --numRows=%d\t numCols=%d\n", numRows, numCols));

    frameSize.width = width; frameSize.height = height;
    [self getEnoughNumRows:&nrows numCols:&ncols forSize:&frameSize];
    
    // if columns or rows are short for this size, make new cells
    if (numCols < ncols) {
	// make columns
	for (i = ncols - numCols; i > 0; --i) {
	    [self addCol];
	}
    }    
    if (numRows < nrows) {
	// make rows
	for (i = nrows - numRows; i > 0; --i) {
	    [self addRow];
	}
    }
    
    DBG(10,fprintf(stderr," ++size.width=%f\t size.height=%f\n",
		    		frame.size.width,frame.size.height));
    DBG(10,fprintf(stderr," ++numRows=%d\t numCols=%d\n", numRows, numCols))
    return ([super sizeTo:width :height]);
}

- saveDirFile
{
    NXStream	*dirMemStream;
    int		i;
    int		irow, icol;
    id		tcell;
    char	buf[256];
    
    if (strlen(iDirFileName) == 0) {
	// dir file name is not set yet
	return NULL;
    }
    if ((dirMemStream = NXOpenMemory(NULL, 0, NX_WRITEONLY)) == NULL) {
	// could not open stream
	fprintf(stderr," NewsBase:IFolderDockMarix: memory open error\n");
	return NULL;
    }
    
    // element at 0 is root(nextStatin), so does not need to save
    i = 1;
    while (tcell=[cellList objectAt:i]) {
	// cellList holds all cell in this matrix
	if ([tcell title] == NULL) {
	    // pointer of title should not be NULL
	    [tcell setTitle:""];
	}
	if (strlen([tcell title]) != 0) {
	    // cell is not blank cell
	    [self getRow:&irow andCol:&icol ofCell:tcell];
	    NXPrintf(dirMemStream,"%d %d %s\n", irow, icol, [tcell title]);
	}
	++i;
    }
    if (NXSaveToFile (dirMemStream, iDirFileName) != 0 ) {
	sprintf(buf,"error occured writing data to file \"%.90s\"",
							iDirFileName);
	NXRunAlertPanel(LoStr("NewsBase"),LoStr(buf),LoStr("OK"),NULL,NULL);
    }
    NXCloseMemory(dirMemStream, NX_FREEBUFFER);
    return self;
}

- readDirFile
{
    NXStream	*fileStream;
    int		irow, icol;
    char	cellTitle[128];
    int		i;
    id		tcell;
    
    if (strlen(iDirFileName) == 0) {
	return NULL;
    }
    if ((fileStream = NXMapFile(iDirFileName, NX_READONLY)) == NULL) {
	// file mapping failed
	fprintf(stderr,"INewsBase:IFolderDockMatrix: can't map .dir.newsbase"
			" file\n");
	return NULL;
    }
    while (NXScanf(fileStream, "%d %d %127s\n",&irow,&icol,cellTitle) == 3) {
	if (irow > (numRows-1)) {
	    // not enough rows
	    for (i = numRows; i <= irow; ++i) {
		[self addRow];
	    }
	}
	if (icol > (numCols-1)) {
	    // not enough cols
	    for (i = numCols; i <= icol; ++i) {
		[self addCol];
	    }
	}
	// set cell stored in .dir.newsbase
	tcell = [self cellAt:irow :icol];
	[tcell setImage:[NXImage findImageNamed:CLOSEDFOLDER]];
	[tcell setTitle:cellTitle];
    }
    NXCloseMemory (fileStream, NX_FREEBUFFER);
    return self;
}

- (void)getEnoughNumRows:(int *)rows numCols:(int *)cols 
				forSize:(NXSize *)frameSize
{
    *cols = floor (frameSize->width/(cellSize.width + intercell.width));
    *rows = rint (frameSize->height/(cellSize.height + intercell.height));
    return;
}


///* delegate method for NXSplitView */
//
//#define		SCRLLMATRIX_HEIGHT	107  // height for oNewsfolderScroll
//
//- splitView:sender resizeSubviews:(const NXSize *)oldSize
//{
//    id		upperView, lowerView;
//    NXRect	viewFrame, upperFrame;
//    int		ncols, nrows;
//    int		i, j;
//    
//    DBG(1,fprintf(stderr,"-- splitView:\n"));
//    upperView = *(NX_ADDRESS([sender subviews]));
//    lowerView = *(NX_ADDRESS([sender subviews]) + 1);
//
//    [[sender window] disableDisplay];
//    [sender adjustSubviews];
//
//    // adjust upper(self) view size
//    [sender getFrame:&viewFrame];
//    [upperView getFrame:&upperFrame];	// IFolderDockMatrix rectangle
//    [self getEnoughNumRows:&nrows numCols:&ncols 
//	    				forSize:&(upperFrame.size)];
//    upperFrame.size.height = cellSize.height * nrows +
//    						 intercell.height * (nrows-1);
//    [upperView setFrame:&upperFrame];
//    
//    // compute lower view size
//    viewFrame.origin.y = [sender dividerHeight] + upperFrame.size.height;
//    					// coord. is flipped in NXSplitView
//    viewFrame.size.height -= viewFrame.origin.y;
//    [lowerView setFrame:&viewFrame];    
//
//    [[sender window] reenableDisplay];
//    
//    // unregister cell's frame to viewRectList in AcceptWindow
//    // so that the clipped cell can not be used as dropped well
//    
//    if (numCols > ncols) {
//	// remove columns
//	for (i = (numCols-1); i > (ncols-1); --i) {
//	    // unregister rect of cell which will be clipped by ScrollView,
//	    // which is a superview of this class
//	    for (j = (numRows-1); j >= 0; --j) {
//		[self unregisterCellAt:j :i window:window];
//	    }
//	}
//    }
//    
//    if (numRows > nrows) {
//	// remove rows
//	for (i = (numRows-1); i > (nrows-1); --i) {
//	    // unregister rect of cell which will be clipped by ScrollView,
//	    // which is a superview of this class
//	    for (j = (numCols-1); j >= 0; --j) {
//		[self unregisterCellAt:i :j window:window];
//	    }
//	}
//    }
//    
//    return self;
//}
//
//- splitView:sender getMinY:(NXCoord *)minY maxY:(NXCoord *)maxY
//						ofSubviewAt:(int)offset
//{
//    NXRect	viewFrame;
//    int		nrows, ncols;
//
//    *minY = 0.0;
//    [sender getFrame:&viewFrame];
//    viewFrame.size.height -= SCRLLMATRIX_HEIGHT;
//    [self getEnoughNumRows:&nrows numCols:&ncols 
//	    				forSize:&(viewFrame.size)];
//    nrows -= 1;			// avoid that the upperview size will be 
//    				// overflow because of rounding nrows
//    if (nrows >= 1) {
//	*maxY = cellSize.height * nrows + intercell.height * (nrows -1);
//    } else {
//	*maxY = 0.0;
//    }
//    
//    return self;
//}
//


@end
